home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Archive / Graphics / QuickDraw GX / GX->PostScript Sample / GXToPostScript / Imaging Engine / TextStylePrimitives.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  43.5 KB  |  1,637 lines  |  [TEXT/MPS ]

  1. /*
  2.      File:        TextStylePrimitives.c
  3.  
  4.      Contains:    QuickDraw GX to PostScript conversion code.
  5.                          File contains primitive routines for setting
  6.                         text styles, includeing font, size, and text-face.
  7.  
  8.      Version:    Technology:    Quickdraw GX 1.1.x
  9.       
  10.      Copyright:    © 1990-1997 by Apple Computer, Inc., all rights reserved.
  11. */
  12.  
  13. #include "GXToPSBuildConfig.h"
  14. #include <GXGraphics.h>
  15. #include "GXGraphicsPriv.h"
  16. #include <GXEnvironment.h>
  17. #include "GXToPostScript.h"
  18. #include "IOUtilities.h"
  19. #include "RDUtil.h"
  20. #include "FontHandler.h"
  21. #include "PublicPostScriptIE.h"
  22. #include "private.h"
  23. #include "PSIEResources.h"
  24. #include "GXErrors.h"
  25. #include "ShapeUtilities.h"
  26. #include <String.h>
  27.  
  28. #ifdef resumeLabel
  29.     #undef resumeLabel
  30. #endif
  31. #define resumeLabel(exception)
  32.  
  33. /**********************************
  34.  
  35.     Routine tests to see if we should use
  36.     the fast case of the BuildChar routine
  37.     in the PostScript text face code.
  38.     
  39.     This case handles a subset of all text faces
  40.     and implements white layers as drawing white
  41.     rather than clipping so output is incorrect
  42.     if drawn on top of other objects.
  43.     
  44.     ** KEEP IN SYNC WITH TEXTFACEPROCS.PS **
  45.     
  46.     LW8LayerBuildChar only ignores:
  47.         outlineStyle (except pen width if framed layer)
  48.         boldOutset
  49.         whiteLayer transparency
  50.         autoAdvance
  51.         
  52.     Current implementation only returns true for
  53.     QuickDraw shadow text from translator for two
  54.     byte fonts.  (also, no autoAdvance)
  55.     
  56. ***********************************/
  57. Boolean TestUseLW8BuildChar(gxTextFace *theFace, gxStyle theStyle);
  58. Boolean TestUseLW8BuildChar(gxTextFace *theFace, gxStyle theStyle)
  59.     {
  60.         #pragma unused(theFace)
  61.         
  62.         Style            theQDStyle;
  63.         long            len;
  64.         gxTag            theTag;
  65.         Boolean        useIt = false;
  66.         
  67.  
  68.         /* Auto Advance requires the general case BuildChar */
  69.  
  70.         if (GXGetStyleTextAttributes(theStyle) & gxAutoAdvanceText)
  71.             return(false);
  72.                     
  73.         /* See if style is tagged with QuickDraw style */
  74.  
  75.         if (GXGetStyleTags(theStyle, textFaceTagType, 1, gxSelectToEnd, nil) > 0) {
  76.  
  77.             GXGetStyleTags(theStyle, textFaceTagType, 1, 1, &theTag);
  78.             len = GXGetTag(theTag, nil, &theQDStyle);
  79.  
  80.             check ( len == sizeof(Style) );
  81.             
  82.             if ( theQDStyle & shadow ) {
  83.             
  84.                 /*
  85.                     Now check to see if the translation target was PostScript - 
  86.                         if it isn't then we can't use optimized buildchar
  87.                 */
  88.                 
  89.                 if ( GXGetStyleTags(theStyle, targetTagType, 1, gxSelectToEnd, nil) > 0 ) {
  90.  
  91.                     long        target;
  92.                     GXGetStyleTags(theStyle, targetTagType, 1, 1, &theTag);
  93.                     len = GXGetTag(theTag, nil, &target);
  94.                     
  95.                     check ( len = sizeof(long) );
  96.                     
  97.                     if ( (target == 0) || (target == gxPostScriptTargetTranslation ) )
  98.                         useIt = true;
  99.                 
  100.                 } else {
  101.                 
  102.                     /* No target tag, let's assume we can use it - less risky of a change at this point 2/16/95 */
  103.                     
  104.                     useIt = true;
  105.                     
  106.                 }//end if
  107.                 
  108.             }//end if
  109.             
  110.         }//end if
  111.     
  112.         return(useIt);
  113.     
  114.     }//TestUseLW8BuildChar
  115.  
  116. //<FF>
  117. /**********************************
  118.  
  119.     Routine tests to see if a text face can be
  120.     handled by the MakeSimpleLayeredFont PS proc.
  121.     
  122.     Can be if:
  123.         1.    #layers == 1
  124.         2.    AutoAdvance is false.
  125.         3.    Layer is evenOdd or windingNumber filled
  126.         4.    Layer has nil style
  127.         5.    Layer has transform that has fullShape clip.
  128.         6.    Layer's transform's mapping matches advance mapping.
  129.         7.  Layer's Bold Outset is 0,0
  130.         
  131. ************************************/
  132. Boolean TestSimpleFace(gxTextFace *theFace, gxStyle theStyle);
  133. Boolean TestSimpleFace(gxTextFace *theFace, gxStyle theStyle)
  134.     {
  135.         gxTransform            aTransform;
  136.         gxMapping                aMapping;
  137.         gxShapeFill            layerFill;
  138.         
  139.         /* Check # 1 */
  140.         if (theFace->faceLayers != 1) 
  141.             return(false);
  142.             
  143.         /* Check # 2 */
  144.         if (GXGetStyleTextAttributes(theStyle) & gxAutoAdvanceText)
  145.             return(false);
  146.  
  147.         /* check # 3 */
  148.         layerFill = theFace->faceLayer[0].outlineFill;
  149.         if ( (layerFill != gxEvenOddFill) && ( layerFill != gxWindingFill) )
  150.             return(false);
  151.         
  152.         /* check # 4 */
  153.         if (theFace->faceLayer[0].outlineStyle != nil)
  154.             return(false);
  155.  
  156.         /* check #5 and #6 */
  157.         aTransform = theFace->faceLayer[0].outlineTransform;
  158.         
  159.         if (aTransform != nil) {
  160.         
  161.             if (GetTransformClipType(aTransform) != gxFullType)
  162.                 return(false);
  163.                 
  164.             GXGetTransformMapping(aTransform, &aMapping);
  165.             
  166.             if (!TestMappingEqual(&aMapping, &(theFace->advanceMapping) ) )
  167.                 return(false);
  168.             
  169.         } else {        // nil transform means identity mapping for layer so test advance for identity too.
  170.         
  171.             if ( !TestMappingIdentity(&(theFace->advanceMapping)) )
  172.                 return(false);
  173.         
  174.         }//end if
  175.         
  176.         /* check #7 */
  177.         if ( (theFace->faceLayer[0].boldOutset.x != 0) || (theFace->faceLayer[0].boldOutset.y != 0) )
  178.             return(false);
  179.             
  180.  
  181.         /* Passed all tests, return true */
  182.         
  183.         return(true);
  184.     
  185.     }//TestSimpleFace
  186.  
  187.  
  188. /************************************
  189.     MakeTransformDict:
  190.     
  191.     Convert the gx graphics transform into a PostScript Dictionary
  192.     
  193.     If the transform is nil, then a transform dictionary
  194.     for the identity transform will be generated.
  195.     
  196.     hIEGlobals:            the Imaging Engine globals
  197.     theTransform:        The transform to translate.
  198.     
  199. *************************************/
  200. OSErr MakeTransformDict(TIEGlobalsHdl hIEGlobals, gxTransform theTransform)
  201.     {
  202.         OSErr                            status = noErr;
  203.         gxMapping                    theMapping;
  204.         gxShape                        theClip;
  205.         TRDParams*                pRDParams;
  206.         gxShapeType                clipType;
  207.         gxShapeFill                clipFill;
  208.         Boolean                        transformWasNil = false;
  209.         
  210.         if (theTransform == nil) {
  211.             transformWasNil = true;
  212.             theTransform = GXNewTransform();
  213.         }//end if
  214.             
  215.         
  216.         GXGetTransformMapping(theTransform, &theMapping);
  217.         nrequire(TestMappingPerspective(&theMapping), failed_HasPerspective);            // Remove eventually and support perspective.
  218.         
  219.         theClip = GXGetTransformClip(theTransform);
  220.         clipType = GXGetShapeType(theClip);
  221.         clipFill = GXGetShapeFill(theClip);
  222.         
  223.         pRDParams = (*hIEGlobals)->pRDParams;    
  224.         
  225.  
  226.         /** Put parameters for MakeTrDict on operand stack **/
  227.         
  228.         /*** The clip geometry procedure ***/
  229.         
  230.         status = GeometryDrone(hIEGlobals, theClip, eClipGeometry + eMakeProcedure, nil, 0);
  231.         nrequire(status, failed_Geometry);
  232.         
  233.         /*** The clip fill key ***/
  234.         
  235.         status = DoFillKey(pRDParams, clipFill);
  236.         nrequire(status, failed_Output);
  237.         
  238.         /** The Mapping, of course perspective is ignored **/
  239.         
  240.         pRDParams->resIndex = kDoMapping;
  241.         status = RDResPrintf(pRDParams, theMapping.map[0][0], theMapping.map[0][1],
  242.                                                                         theMapping.map[1][0], theMapping.map[1][1],
  243.                                                                         theMapping.map[2][0], theMapping.map[2][1],
  244.                                                                         theMapping.map[2][2]
  245.                                                 );
  246.         nrequire(status, failed_Output);
  247.         
  248.         
  249.         /** Now execute the MakeTrDict oprator, leaving a transform dictionary on the stack **/
  250.         
  251.         pRDParams->resIndex = kMakeTrDict;
  252.         status = RDResPrintf(pRDParams);
  253.         nrequire(status, failed_Output);
  254.         
  255.         if (transformWasNil)
  256.             GXDisposeTransform(theTransform);
  257.         
  258.         status = GXGetGraphicsError(nil);
  259.         ncheck(status);
  260.         
  261. failed_Geometry:        
  262. failed_Output:
  263.  
  264.         GXDisposeShape(theClip);
  265.  
  266.  
  267. failed_HasPerspective:
  268.         
  269.         return(status);
  270.         
  271.     }//MakeTransformDict
  272.  
  273. //<FF>
  274. /**************************
  275.     Routine MakeStyleDict:
  276.     
  277.     
  278.     Routine converts a gx graphics style into 
  279.     a PostScript style dictionary.
  280.     
  281.     A nil style implies (could only come from a text face layer):
  282.         dash, pattern, join, caps, all nil
  283.         penSize: 0
  284.         textSize: 1
  285.  
  286. ****************************/
  287. OSErr MakeStyleDict(TIEGlobalsHdl hIEGlobals, gxStyle theStyle)
  288.     {
  289.         OSErr                                status;
  290.         gxPatternRecord            thePattern;
  291.         gxDashRecord                theDash;
  292.         gxJoinRecord                theJoin;
  293.         long                                i;                                        // An integer.
  294.         gxStyleAttribute        theAttributes;
  295.         TRDParams                        *rdParams;
  296.  
  297.  
  298.         rdParams = (*hIEGlobals)->pRDParams;
  299.  
  300.         if (theStyle != nil) {
  301.         
  302.             thePattern.pattern = nil;
  303.             theDash.dash = nil;
  304.             theJoin.join = nil;
  305.             
  306.             theAttributes = GXGetStyleAttributes(theStyle);
  307.             
  308.             /*** Put all of the parameters for MakeStyleDict on the operand stack ***/
  309.             
  310.             /*** Pattern dictionary ****/
  311.             
  312.             GXGetStylePattern(theStyle, &thePattern);
  313.             if (thePattern.pattern != nil)            
  314.                 status = MakePatternDict(hIEGlobals, &thePattern, theAttributes);
  315.             else
  316.                 status = DoNull(rdParams);
  317.             
  318.             nrequire(status, failed_Dict);
  319.             
  320.             
  321.             /**** right is in ****/
  322.                         
  323.             rdParams->resIndex = kDoBoolean;
  324.             status = RDResPrintf(rdParams, theAttributes & gxAutoInsetStyle ? (long)true : (long)false);
  325.             nrequire(status, failed_Dict);
  326.             
  327.             
  328.             /*** frame type ***/
  329.                     
  330.             rdParams->resIndex = kDoInt;
  331.             status = RDResPrintf(rdParams, GetPSFrameValue(theAttributes));
  332.             nrequire(status, failed_Dict);
  333.             
  334.                     
  335.             /*** Dash dictionary ***/
  336.             
  337.             GXGetStyleDash(theStyle, &theDash);
  338.             if (theDash.dash != nil)            
  339.                 status = MakeDashDict(hIEGlobals, &theDash, theAttributes);
  340.             else
  341.                 status = DoNull(rdParams);
  342.             
  343.             nrequire(status, failed_Dict);
  344.             
  345.             /**** pen thickness ****/
  346.             
  347.             rdParams->resIndex = kDoFixed;
  348.             status = RDResPrintf(rdParams, GXGetStylePen(theStyle));
  349.             nrequire(status, failed_Dict);
  350.             
  351.             /** line cap **/
  352.             
  353.             status = GetPSLineCap(theStyle, &i);
  354.             nrequire(status, failed_Dict);
  355.             if (i == -1)                                    // must be a shape cap, treat it as butt for the style dict.
  356.                 i = 0;
  357.             rdParams->resIndex = kDoInt;
  358.             status = RDResPrintf(rdParams, i);
  359.             nrequire(status, failed_Dict);
  360.             
  361.             /** line join **/
  362.             
  363.             GXGetStyleJoin(theStyle, &theJoin);
  364.             i = GetPSLineJoin(&theJoin);
  365.             if (i == -1)                                    // must be a shape join, treat it as flat for the style dict.
  366.                 i = 0;
  367.             rdParams->resIndex = kDoInt;
  368.             status = RDResPrintf(rdParams, i);
  369.             nrequire(status, failed_Dict);
  370.             
  371.             /** Miter limit **/
  372.             
  373.             rdParams->resIndex = kDoFixed;
  374.             status = RDResPrintf(rdParams, SkiaMiterToPS(theJoin.miter, GXGetStylePen(theStyle)));
  375.             nrequire(status, failed_Dict);
  376.             
  377.             /** grid fitting **/
  378.             
  379.             rdParams->resIndex = kDoBoolean;
  380.             status = RDResPrintf(rdParams, theAttributes & gxDeviceGridStyle ? (long)true : (long) false);
  381.             nrequire(status, failed_Dict);
  382.             
  383.             
  384.             /** Do the text size **/
  385.             rdParams->resIndex = kDoFixed;
  386.             status = RDResPrintf(rdParams, GXGetStyleTextSize(theStyle));
  387.             nrequire(status, failed_Dict);
  388.                         
  389.             nrequire(status = GXGetGraphicsError(nil), failed_Dict);
  390.             
  391.             /**** Now make it all into a style dictionary, leave dict on operand stack *****/
  392.             
  393.             rdParams->resIndex = kMakeStyleDict;
  394.             status = RDResPrintf(rdParams);
  395.             ncheck(status);
  396.             
  397.     failed_Dict:
  398.     failed_Cap:
  399.             /** Dispose of any shapes accumulated in obtaining style stuff **/
  400.             
  401.             if (thePattern.pattern != nil)
  402.                 GXDisposeShape(thePattern.pattern);
  403.             
  404.             if (theDash.dash != nil)
  405.                 GXDisposeShape(theDash.dash);
  406.             
  407.             if (theJoin.join != nil)
  408.                 GXDisposeShape(theJoin.join);
  409.                 
  410.         } else {
  411.         
  412.             /** the style passed in was nil, output the nil style dictionary **/
  413.             
  414.             rdParams->resIndex = knilStyleDict;
  415.             status = RDResPrintf(rdParams);
  416.             ncheck(status);
  417.             
  418.         }//end if    
  419.  
  420.         return(status);
  421.     
  422.     }//MakeStyleDict
  423.  
  424.  
  425.  
  426. /******************************
  427.     Function:        TestStyleFace
  428.     
  429.     Function returns true if the style
  430.     contains a text face
  431.     
  432.     There is a text face if:
  433.         the #layers > 0
  434.             or
  435.         the advance mapping is not identity.
  436.     
  437. *******************************/
  438. Boolean TestStyleFace(gxStyle theStyle);
  439. Boolean TestStyleFace(gxStyle theStyle)
  440.     {
  441.         gxTextFace        theFace;
  442.         long                    nLayers;
  443.         Boolean                hasFace = true;                    // initialize to true, false is indicated by elimination.
  444.         
  445.         nLayers = GXGetStyleFace(theStyle, nil);
  446.                 
  447.         if (nLayers == -1) {                            // undocumented feature.
  448.         
  449.             hasFace = false;
  450.         
  451.         } else if (nLayers == 0)    {                // If number of layers is 0, then check advance mapping.
  452.                 
  453.             GXGetStyleFace(theStyle, &theFace);
  454.                         
  455.             if (TestMappingIdentity(&(theFace.advanceMapping)))                
  456.                 hasFace = false;
  457.             
  458.         } else if (GXGetStyleTags(theStyle, textFaceTagType, 1, gxSelectToEnd, nil) > 0 ) {
  459.  
  460.             gxTag            theTag;
  461.             Style            theQDStyle;
  462.             long            len;
  463.  
  464.             /******
  465.                 If the textFaceTagType tag on the text face is simple underline, then
  466.                 we can lie and say there is no text face because the PS text
  467.                 face code doesn't do underlines anyway.
  468.                 
  469.                 This makes us go faster and avoids a 1 pixel clipping problem in
  470.                 the text face code for small point sizes
  471.             ******/    
  472.         
  473.             GXGetStyleTags(theStyle, textFaceTagType, 1, 1, &theTag);
  474.             len = GXGetTag(theTag, nil, &theQDStyle);
  475.             #if DEBUGLEVEL > 1
  476.                 if (len > sizeof(Style))
  477.                     dprintf(notrace, "Fatal error, tfac tag was not a QD Style, size: %d", len);
  478.             #endif
  479.             
  480.             if (theQDStyle == underline)
  481.                 hasFace = false;
  482.                 
  483.         }//end if
  484.  
  485.         return(hasFace);    
  486.     
  487.     }//TestStyleFace
  488.  
  489. //<FF>
  490. /*******************************
  491.  
  492.     MakeFaceFontName:
  493.     
  494.     Combines the font name with the
  495.     text face tags so that text face
  496.     fonts can be resused by the PostScript
  497.     procedures.
  498.     
  499.         Example: Helvetica with bold face at 12 points would be:
  500.             Helvetica$01$000C0000
  501.  
  502.                     the $01 is the QD face.
  503.                     the $000C0000 is the Fixed point size.
  504.                     
  505.     return value:  Did the name get changed?
  506.     
  507. ********************************/
  508. Boolean MakeFaceFontName(gxStyle theStyle, Str255 fontName);
  509. Boolean MakeFaceFontName(gxStyle theStyle, Str255 fontName)
  510.     {
  511.         Boolean        changedIt = false;
  512.         gxTag            theTag;
  513.         Style            theQDStyle;
  514.         long            len;
  515.         long            nTags;
  516.         long            newLength;
  517.         Fixed            pointSize;
  518.         
  519.         /*****
  520.             Combine the name passed in with the text face tag
  521.             (QD style converted to hex appended to name)
  522.         *****/
  523.         nTags = GXGetStyleTags(theStyle, textFaceTagType, 1, gxSelectToEnd, nil);
  524.         if (nTags > 0) {
  525.  
  526.             GXGetStyleTags(theStyle, textFaceTagType, 1, 1, &theTag);
  527.             len = GXGetTag(theTag, nil, &theQDStyle);
  528.             #if DEBUGLEVEL > 1
  529.                 if (len > sizeof(Style))
  530.                     dprintf(notrace, "Fatal error, tfac tag was not a QD Style, size: %d", len);
  531.             #endif
  532.             
  533.             /* PS Procs don't do underlining so ignore */
  534.             theQDStyle &= ~underline;
  535.                             
  536.             len = fontName[0];
  537.             newLength = len + 1 + 2 * sizeof(Style);            // Add 1 for '$' and hex length of a style
  538.             if (nTags > 1)
  539.                 newLength += 1 + 2 * sizeof(Fixed);                    // Add 1 for '$' and hex length of a Fixed.
  540.                 
  541.             if (newLength <= 128) {
  542.             
  543.                 fontName[len + 1] = '$';
  544.                 HexBlockMove(&theQDStyle, fontName + len + 2, sizeof(Style));
  545.                 fontName[0] += 1 + 2 * sizeof(Style);
  546.                 
  547.                 /* If there is a second tag, then it must be the Fixed point size combine the name */
  548.                 if (nTags > 1) {
  549.                 
  550.                     GXGetStyleTags(theStyle, textFaceTagType, 2, 1, &theTag);
  551.                     len = GXGetTag(theTag, nil, &pointSize);
  552.                     #if DEBUGLEVEL > 1
  553.                         if (len > sizeof(Fixed))
  554.                             dprintf(notrace, "Fatal error, 2nd tfac tag was not a fixed, size: %d", len);
  555.                     #endif
  556.  
  557.                     len = fontName[0];
  558.                     fontName[len + 1] = '$';
  559.                     HexBlockMove((unsigned char*)&pointSize, fontName + len + 2, sizeof(Fixed));
  560.                     fontName[0] += 1 + 2 * sizeof(Fixed);
  561.                     
  562.                 }//end if
  563.                 
  564.                 changedIt = true;
  565.             
  566.             } else {
  567.             
  568.                 #if DEBUGLEVEL > 1
  569.                 dprintf(trace, "Text Face name exceeded 128 characters, not caching");
  570.                 #endif
  571.                 
  572.             }//end if
  573.                     
  574.         }//end if
  575.         
  576.         return(changedIt);
  577.     
  578.     }//MakeFaceFontName
  579.  
  580.  
  581.  
  582. /*******************************
  583.  
  584.     Function: OutputPSStyleMappedName
  585.     
  586.     Function outputs a name for the potential
  587.     font to substitute for the style which is
  588.     stored in the 'gxPostscriptFontNameSynonymTag' tag.
  589.     
  590. ********************************/
  591. OSErr OutputPSStyleMappedName(TIEGlobalsHdl hIEGlobals, gxStyle theStyle);
  592. OSErr OutputPSStyleMappedName(TIEGlobalsHdl hIEGlobals, gxStyle theStyle)
  593.     {
  594.         OSErr                            status;
  595.         unsigned char            fontName[130];
  596.         TRDParams                    *rdParams;
  597.         gxTag                            theTag;
  598.         long                            len;
  599.         
  600.         if (GXGetStyleTags(theStyle, gxPostscriptFontNameSynonymTag, 1, gxSelectToEnd, nil) > 0) {
  601.             
  602.             GXGetStyleTags(theStyle, gxPostscriptFontNameSynonymTag, 1, 1, &theTag);
  603.             len = GXGetTag(theTag, nil, nil);
  604.             check (len <= 128);
  605.             
  606.             GXGetTag(theTag, nil, fontName + 1);
  607.             
  608.             fontName[0] = '/';                    // prefix with slash.
  609.             fontName[len + 1] = ' ';        // space seperator.
  610.             len += 2;
  611.             
  612.         } else {
  613.         
  614.             memcpy(fontName, "/GXNoName", 9);
  615.             len = 9;
  616.             
  617.         }//end if
  618.         
  619.         rdParams = (*hIEGlobals)->pRDParams;
  620.         rdParams->resIndex = kDoString;
  621.         status = RDResPrintf(rdParams, fontName, len);
  622.         ncheck(status);
  623.         
  624.         return(status);
  625.         
  626.     }//OutputPSStyleMappedName
  627.  
  628.  
  629. //<FF>
  630. /****************************************
  631.  
  632.     ApplyLayerTransformToRect
  633.     
  634.     Routine finds the new rectangle that
  635.     encloses the rectangle passed in, mapped
  636.     by the transform.
  637.     
  638.     tr:            Transform to use.
  639.     rect:        Array of 2 points, first is top-left, second is bottom-right.
  640.     
  641. *****************************************/
  642. void ApplyLayerTransformToRect(gxTransform tr, gxRectangle *rect);
  643. void ApplyLayerTransformToRect(gxTransform tr, gxRectangle *rect)
  644.     {
  645.         gxPoint            rectPoints[4];
  646.         gxMapping        map;
  647.         long                i;
  648.         
  649.         if (tr == nil)
  650.             return;
  651.         
  652.         /* Make the 4 points of the rectangle */
  653.         
  654.         // top-left
  655.         rectPoints[0].x = rect->left;
  656.         rectPoints[0].y = rect->top;
  657.         
  658.         // top-right.
  659.         rectPoints[1].x = rect->right;
  660.         rectPoints[1].y = rect->top;
  661.         
  662.         // bottom-right.
  663.         rectPoints[2].x = rect->right;
  664.         rectPoints[2].y = rect->bottom;
  665.         
  666.         // bottom-left.
  667.         rectPoints[3].x = rect->left;
  668.         rectPoints[3].y = rect->bottom;
  669.         
  670.         /* map them */
  671.         
  672.         MapPoints( GXGetTransformMapping(tr, &map), 4, rectPoints);
  673.         
  674.         /* Now find the bounding box of the four points */
  675.         rect->left = rectPoints[0].x;
  676.         rect->right = rect->left;
  677.         rect->top = rectPoints[0].y;
  678.         rect->bottom = rect->top;
  679.         
  680.         for (i = 1; i <= 3; ++i) {
  681.  
  682.             if (rectPoints[i].x < rect->left)
  683.                 rect->left = rectPoints[i].x;
  684.                 
  685.             if (rectPoints[i].x > rect->right)
  686.                 rect->right = rectPoints[i].x;
  687.                 
  688.             if (rectPoints[i].y < rect->top)
  689.                 rect->top = rectPoints[i].y;
  690.                 
  691.             if (rectPoints[i].y > rect->bottom)
  692.                 rect->bottom = rectPoints[i].y;
  693.             
  694.         }//end for
  695.             
  696.     }//ApplyLayerTransformToRect
  697.  
  698. //<FF>
  699. /****************************************
  700.  
  701.     OutputFaceBoundingBox:
  702.     
  703.     Function outputs the bounding box of the text face
  704.     as a PostScript array
  705.     
  706. ******************************************/
  707. OSErr        OutputFaceBoundingBox(TIEGlobalsHdl hIEGlobals, gxStyle theStyle, gxTextFace *pFace);
  708. OSErr        OutputFaceBoundingBox(TIEGlobalsHdl hIEGlobals, gxStyle theStyle, gxTextFace *pFace)
  709.     {
  710.         OSErr                            status;
  711.         TRDParams                    *rdParams;
  712.         gxFontVariation        *variations = nil;
  713.         long                            axisCount;
  714.         gxRectangle                fontBBox, faceBBox;
  715.         gxRectangle                layerRect;
  716.         Fixed                            temp;
  717.         gxFaceLayer                *pLayer;
  718.         long                            idx;
  719.         
  720.         rdParams = (*hIEGlobals)->pRDParams;
  721.  
  722.         axisCount = GXGetStyleFontVariationSuite(theStyle, nil);
  723.         if (axisCount > 0) {
  724.  
  725.             status = PrNewPtr((Ptr *) &variations, axisCount * sizeof(gxFontVariation) );
  726.             nrequire(status, failed_newPtr);
  727.             
  728.             GXGetStyleFontVariationSuite(theStyle, variations);
  729.         
  730.         }//endif
  731.         
  732.         GXPrivateGetFontBounds(GXGetStyleFont(theStyle), axisCount, variations, &fontBBox);
  733.         
  734. #if DEBUGLEVEL > 1
  735.         status = RDFlushBuffer(rdParams->rdMap);
  736.         if (status == noErr)
  737.             status = (*hIEGlobals)->psDevice->BufferData("% original: ", 12, gxNoBufferOptions);
  738.         if (status == noErr) {            
  739.             rdParams->resIndex = kDoBBox;
  740.             status = RDResPrintf(rdParams, fontBBox.left, fontBBox.top, fontBBox.right, fontBBox.bottom);
  741.             nrequire(status, failed_Output);
  742.         }
  743. #endif
  744.  
  745.         /* Negate the Y's and swap top and bottom because Font coordinate system is flipped from gx graphics */
  746.         
  747.         temp = fontBBox.top;        
  748.         fontBBox.top = -fontBBox.bottom;
  749.         fontBBox.bottom= -temp;
  750.         
  751.  
  752.         if ( (fontBBox.top != 0) || (fontBBox.bottom != 0) || (fontBBox.left != 0) || (fontBBox.right != 0) ) {
  753.         
  754.             /** Now properly produce the text face's bounding box by applying the layer's information to the font's bbox **/
  755.             
  756.             faceBBox = fontBBox;
  757.             pLayer = pFace->faceLayer;
  758.             for (idx = 0; idx < pFace->faceLayers; ++idx, ++pLayer) {
  759.             
  760.                 /* Compute the bounding box if layer has a fill */
  761.                 
  762.                 if (pLayer->outlineFill != gxNoFill) {
  763.                         
  764.                     /** Compute layer's bounding box, start with font's bounding box **/
  765.                     
  766.                     layerRect = fontBBox;
  767.                     
  768.                     /* Scale the layer's bounding by the layer's point size */
  769.                     
  770.                     if (pLayer->outlineStyle != nil) {
  771.                     
  772.                         Fixed        size = GXGetStyleTextSize(pLayer->outlineStyle);
  773.                                             
  774.                         layerRect.left = FixedMultiply(layerRect.left, size);
  775.                         layerRect.top = FixedMultiply(layerRect.top, size);
  776.                         layerRect.right = FixedMultiply(layerRect.right, size);
  777.                         layerRect.bottom = FixedMultiply(layerRect.bottom, size);
  778.                                         
  779.                     }//end if
  780.                                 
  781.         
  782.                     /** Expand layer's bounding box by boldness **/
  783.         
  784.                     layerRect.left -= pLayer->boldOutset.x;
  785.                     layerRect.right += pLayer->boldOutset.x;
  786.                     layerRect.top -= pLayer->boldOutset.y;
  787.                     layerRect.bottom += pLayer->boldOutset.y;
  788.         
  789.                     /* If framed, expand by pen and dash bounding box */
  790.                     
  791.                     if ( (pLayer->outlineFill == gxFrameFill) || (pLayer->outlineFill == gxClosedFrameFill) ) {
  792.         
  793.                         if (pLayer->outlineStyle != nil) {
  794.                         
  795.                             Fixed        pen = GXGetStylePen(pLayer->outlineStyle);
  796.                         
  797.                             if (DoesStyleHaveDash(pLayer->outlineStyle)) {
  798.                                 
  799.                                 gxDashRecord            aDash;
  800.                                 gxRectangle                bounds;
  801.                                 
  802.                                 GXGetStyleDash(pLayer->outlineStyle, &aDash);
  803.                                 GXGetShapeBounds(aDash.dash, 0, &bounds);
  804.                                 
  805.                                 pen = FixedMultiply(pen, bounds.bottom - bounds.top);
  806.                                 
  807.                                 GXDisposeShape(aDash.dash);
  808.                             
  809.                             }//end if
  810.                             
  811.                             layerRect.left -= pen / 2;
  812.                             layerRect.right += pen / 2;
  813.                             layerRect.top -= pen / 2;
  814.                             layerRect.bottom += pen / 2;
  815.                         
  816.                         }//end if
  817.                     
  818.                     }//end if
  819.         
  820.                     /* Run the points through the layer's transform */
  821.  
  822.                     ApplyLayerTransformToRect(pLayer->outlineTransform, &layerRect);
  823.                                             
  824.                     /** Now add the layer's bounding box to the face's bounding box **/
  825.                     
  826.                     /* Left must be minimum of X's */
  827.                     
  828.                     if (layerRect.left < faceBBox.left)
  829.                         faceBBox.left = layerRect.left;
  830.                         
  831.                     if (layerRect.right < faceBBox.left)
  832.                         faceBBox.left = layerRect.right;
  833.                         
  834.                 
  835.                     /* Right must be maximum of X's */
  836.                     
  837.                     if (layerRect.right > faceBBox.right)
  838.                         faceBBox.right = layerRect.right;
  839.  
  840.                     if (layerRect.left > faceBBox.right)
  841.                         faceBBox.right = layerRect.left;
  842.                         
  843.                 
  844.                     /* Top must be mimimum of Y's */
  845.                     
  846.                     if (layerRect.top < faceBBox.top)
  847.                         faceBBox.top = layerRect.top;
  848.  
  849.                     if (layerRect.bottom < faceBBox.top)
  850.                         faceBBox.top = layerRect.bottom;
  851.                         
  852.                 
  853.                     /* Bottom must be maximum of Y's */
  854.                     
  855.                     if (layerRect.bottom > faceBBox.bottom)
  856.                         faceBBox.bottom = layerRect.bottom;
  857.                     
  858.                     if (layerRect.top > faceBBox.bottom)
  859.                         faceBBox.bottom = layerRect.top;
  860.                     
  861.                                             
  862.                 }//end if Layer isn't noFill
  863.                                                                             
  864.             }//end for
  865.             
  866.             /****
  867.                 Negate the Y's and swap top and bottom again to put back into font space 
  868.                 (Which then gets flipped again by PostScript later - how confusing)
  869.             ****/
  870.             
  871.             temp = faceBBox.top;        
  872.             faceBBox.top = -faceBBox.bottom;
  873.             faceBBox.bottom= -temp;
  874.  
  875.             /** Output the bounding box as an object on the operand stack **/
  876.             
  877.             rdParams->resIndex = kDoBBox;
  878.             status = RDResPrintf(rdParams, faceBBox.left, faceBBox.top, faceBBox.right, faceBBox.bottom);
  879.             nrequire(status, failed_Output);
  880.             
  881.         } else {
  882.         
  883.             /** Font could not tell me bounding box, put null on operand stack **/
  884.             
  885.             status = DoNull(rdParams);
  886.             nrequire(status, failed_Output);
  887.         
  888.         }//end if
  889.         
  890. failed_Output:
  891.  
  892.         if (variations != nil)
  893.             DisposePtr((Ptr)variations);
  894.  
  895. failed_newPtr:
  896.  
  897.         return(status);
  898.     
  899.     }//OutputFaceBoundingBox
  900.  
  901. //<FF>
  902. /****************************************
  903.  
  904.     Routine:             OutputSimpleFaceParams
  905.     
  906.     Routine outputs the parameters for a simple text
  907.     face as defined by the MakeSimpleLayeredFont procedure.
  908.     
  909.     It can handle simple, one layer text faces that involve
  910.     only an outlineTransform in the layer.
  911.     
  912. ******************************************/
  913. OSErr    OutputSimpleFaceParams(TIEGlobalsHdl hIEGlobals, gxTextFace *pFace, gxStyle theStyle);
  914. OSErr    OutputSimpleFaceParams(TIEGlobalsHdl hIEGlobals, gxTextFace *pFace, gxStyle theStyle)
  915.     {
  916.         #pragma unused(theStyle)
  917.         
  918.         OSErr                        status;
  919.         gxMapping                layerMapping;
  920.         TRDParams                *rdParams;
  921.         gxFaceLayer            *pLayer;
  922.             
  923.         rdParams = (*hIEGlobals)->pRDParams;
  924.             
  925.         /* Output the layer's mapping */
  926.  
  927.         pLayer = pFace->faceLayer;
  928.         if (pLayer->outlineTransform == nil)
  929.             ResetMapping(&layerMapping);
  930.         else
  931.             GXGetTransformMapping(pLayer->outlineTransform, &layerMapping);
  932.  
  933.         rdParams->resIndex = kDoMapping;
  934.         status = RDResPrintf(rdParams,     layerMapping.map[0][0], layerMapping.map[0][1],
  935.                                                                         layerMapping.map[1][0], layerMapping.map[1][1],
  936.                                                                         layerMapping.map[2][0], layerMapping.map[2][1],
  937.                                                                         layerMapping.map[2][2]
  938.                                                 );
  939.                                                 
  940.         nrequire(status, failed_Output);
  941.  
  942. failed_Output:
  943.  
  944.         return(status);
  945.         
  946.     }//OutputSimpleFaceParams
  947.  
  948.  
  949. //<FF>
  950. /****************************************
  951.  
  952.     Routine:             OutputGeneralFaceParams
  953.     
  954.     Routine outputs the parameters for a general text
  955.     face as defined by the MakeLayeredFont procedure.
  956.     
  957. ******************************************/
  958. OSErr    OutputGeneralFaceParams(TIEGlobalsHdl hIEGlobals, gxTextFace *pFace, gxStyle theStyle, Str255 fontName);
  959. OSErr    OutputGeneralFaceParams(TIEGlobalsHdl hIEGlobals, gxTextFace *pFace, gxStyle theStyle, Str255 fontName)
  960.     {
  961.         OSErr                        status;
  962.         TRDParams                *rdParams;
  963.         gxFaceLayer            *pLayer;
  964.         long                        nLayers;
  965.         long                        i;
  966.         gxStyle                    aStyle;
  967.             
  968.         rdParams = (*hIEGlobals)->pRDParams;
  969.  
  970.         /*** Put the parameters (except for the font name) for MakeLayeredFont on the operand stack ***/
  971.         
  972.         /** The font name from the 'gxPostscriptFontNameSynonymTag' tag **/
  973.         
  974.         status = OutputPSStyleMappedName(hIEGlobals, theStyle);
  975.         nrequire(status, failed_Output);        
  976.  
  977.  
  978.         /** The font name for the text face font **/
  979.         
  980.         rdParams->resIndex = kFaceFontName;
  981.         if (MakeFaceFontName(theStyle, fontName)) {
  982.             nrequire(status = RDResPrintf(rdParams, fontName), failed_Output);
  983.         } else {
  984.             nrequire(status = RDResPrintf(rdParams, "\pDontCache"), failed_Output);
  985.         }//end if
  986.         
  987.         /* Roll the 2 names behind the base font dictionary so operand stack is: name name fontDict */
  988.  
  989.         rdParams->resIndex = k3minus1Roll;
  990.         nrequire(status = RDResPrintf(rdParams), failed_Output);
  991.         
  992.  
  993.         /** The font bounding box **/
  994.         
  995.         status = OutputFaceBoundingBox(hIEGlobals, theStyle, pFace);
  996.         nrequire(status, failed_Output);
  997.         
  998.         /** The auto advance **/
  999.  
  1000.         rdParams->resIndex = kDoBoolean;
  1001.         nrequire(status = RDResPrintf(rdParams, GXGetStyleTextAttributes(theStyle) & gxAutoAdvanceText ? (long)true : (long)false), failed_Output);
  1002.         
  1003.         /** Now do the advance mapping **/
  1004.         
  1005.         rdParams->resIndex = kDoMapping;
  1006.         status = RDResPrintf(rdParams, pFace->advanceMapping.map[0][0], pFace->advanceMapping.map[0][1],
  1007.                                                                         pFace->advanceMapping.map[1][0], pFace->advanceMapping.map[1][1],
  1008.                                                                         pFace->advanceMapping.map[2][0], pFace->advanceMapping.map[2][1],
  1009.                                                                         pFace->advanceMapping.map[2][2]
  1010.                                                 );
  1011.         nrequire(status, failed_Output);
  1012.         
  1013.                 
  1014.         /***
  1015.                 Now put the array of layers on the stack, an empty array will
  1016.                     be on the stack if the number of layers was zero
  1017.         ***/    
  1018.         
  1019.         nrequire(status = DoBeginArray(hIEGlobals), failed_Output);
  1020.         
  1021.         nLayers = pFace->faceLayers;
  1022.         pLayer = pFace->faceLayer;
  1023.         for (i = 0; i < nLayers; ++i, ++pLayer) {
  1024.             
  1025.             /** Put the parameters for MakeLayerDict on the stack **/
  1026.             
  1027.             /* the Layer fill key */
  1028.             
  1029.             if (pLayer->flags & gxClipLayer)            // Treat clip layers as no fill since they are only for underlining.
  1030.                 pLayer->outlineFill = gxNoFill;
  1031.             
  1032.             nrequire(status = DoFillKey(rdParams, pLayer->outlineFill), failed_Output);
  1033.             
  1034.             /* The white layer bit */
  1035.             
  1036.             rdParams->resIndex = kDoBoolean;
  1037.             nrequire(status = RDResPrintf(rdParams, pLayer->flags & gxWhiteLayer ? (long)true : (long)false), failed_Output);
  1038.  
  1039.             /* The style dictionary */
  1040.             
  1041.             aStyle = pLayer->outlineStyle;
  1042.             nrequire(status = MakeStyleDict(hIEGlobals, aStyle), failed_Output);
  1043.             
  1044.             /* The transform dictionary */
  1045.             
  1046.             nrequire(status = MakeTransformDict(hIEGlobals, pLayer->outlineTransform), failed_Output);
  1047.             
  1048.             /****
  1049.                 The boldness:
  1050.                 
  1051.                 Make sure that there isn't a zero bold value unless they are both zero
  1052.                 Since Boldness is done in PostScript by scaling, a zero value will cause
  1053.                 an undefinedresult error.  If they are both zero, qd2show ignores however
  1054.             ******/
  1055.             
  1056.             if ((pLayer->boldOutset.x != 0) || (pLayer->boldOutset.y != 0)) {
  1057.             
  1058.                 if (pLayer->boldOutset.x == 0)
  1059.                     pLayer->boldOutset.x = 0x00000010;                // A very small number.
  1060.             
  1061.                 if (pLayer->boldOutset.y == 0)
  1062.                     pLayer->boldOutset.y = 0x00000010;                // A very small number.
  1063.             
  1064.             }//end if
  1065.             
  1066.             rdParams->resIndex = kDoPoint;
  1067.             nrequire(status = RDResPrintf(rdParams, &(pLayer->boldOutset)), failed_Output);
  1068.             
  1069.             /* Execute the MakeLayerDict procedure, leaving the layer dictionary on the stack */
  1070.             
  1071.             rdParams->resIndex = kMakeLayerDict;
  1072.             nrequire(status = RDResPrintf(rdParams), failed_Output);
  1073.         
  1074.         }//end for
  1075.         
  1076.         nrequire(status = DoEndArray(hIEGlobals), failed_Output);
  1077.  
  1078.  
  1079.         /* Output boolean for which buildChar to use */
  1080.         
  1081.         rdParams->resIndex = kDoBoolean;
  1082.         nrequire(status = RDResPrintf(rdParams, (long)TestUseLW8BuildChar(pFace, theStyle)), failed_Output);
  1083.  
  1084. failed_Output:
  1085.  
  1086.         return(status);
  1087.  
  1088.     }//OutputGeneralFaceParams
  1089.  
  1090.  
  1091. //<FF>
  1092. /********************************
  1093.  
  1094.     Function:        MakeOptimalPStextFace
  1095.     
  1096.     Routine makes sure the text face is optimized for 
  1097.     PostScript if it came from the quickdraw world.
  1098.     
  1099. *********************************/
  1100. OSErr MakeOptimalPSTextFace(gxStyle theStyle);
  1101. OSErr MakeOptimalPSTextFace(gxStyle theStyle)
  1102.     {
  1103.         OSErr            status = noErr;    
  1104.         gxTag            theTag;
  1105.         long            len;
  1106.         Style            theQDStyle;
  1107.     
  1108.         if (GXGetStyleTags(theStyle, textFaceTagType, 1, gxSelectToEnd, nil) > 0) {
  1109.  
  1110.             GXGetStyleTags(theStyle, textFaceTagType, 1, 1, &theTag);
  1111.             len = GXGetTag(theTag, nil, &theQDStyle);
  1112.  
  1113.             check ( len == sizeof(Style) );
  1114.             
  1115.             /*
  1116.                 Now check to see if the translation target was PostScript - 
  1117.                     if it isn't Let's make it so.
  1118.             */
  1119.             
  1120.             if ( GXGetStyleTags(theStyle, targetTagType, 1, gxSelectToEnd, nil) > 0 ) {
  1121.  
  1122.                 long        target;
  1123.                 GXGetStyleTags(theStyle, targetTagType, 1, 1, &theTag);
  1124.                 len = GXGetTag(theTag, nil, &target);
  1125.                 
  1126.                 check ( len = sizeof(long) );
  1127.                 
  1128.                 if ( target != gxPostScriptTargetTranslation )  {
  1129.                 
  1130.                     #if DEBUGLEVEL > 1
  1131.                     dprintf(trace, "Not spooled for PS, Calling TRSetStyleCommonFace: face: %X, size: %F", theQDStyle, GXGetStyleTextSize(theStyle));
  1132.                     #endif
  1133.                     
  1134.                     TRSetStyleCommonFace( theStyle, (longCommonFace)theQDStyle, GXGetStyleTextSize(theStyle), fixed1, true, 0);
  1135.                     status = GXGetGraphicsError(nil);
  1136.                     ncheck(status);
  1137.                     
  1138.                 }//end if            
  1139.                 
  1140.             }//end if
  1141.             
  1142.         }//end if
  1143.     
  1144.     
  1145.         return(status);    
  1146.     
  1147.     }//MakeOptimalPSTextFace
  1148.  
  1149.  
  1150. //<FF>
  1151. /*******************************
  1152.  
  1153.     Function:        OutputFaceParams
  1154.     
  1155.         Function puts all of the parameters excluding the base font
  1156.         dictonary on the operand stack for MakeLayeredFont.  The
  1157.         base font dictionary is on the stack.
  1158.         
  1159.         hIEGlobals:            the imaging engine globals.
  1160.         theStyle:                the style containing the text face.
  1161.         fontName:                the name of the font we are applying the text face to.
  1162.     
  1163. ********************************/
  1164. OSErr OutputFaceParams(TIEGlobalsHdl hIEGlobals, gxStyle theStyle, Str255 fontName );
  1165. OSErr OutputFaceParams(TIEGlobalsHdl hIEGlobals, gxStyle theStyle, Str255 fontName )
  1166.     {
  1167.         OSErr                            status;
  1168.         TIEGlobalsPtr            pGlobals;
  1169.         gxTextFace                *pFace;
  1170.         gxFaceLayer                *pLayer;
  1171.         long                            nLayers;
  1172.         long                            i;
  1173.         TRDParams                    *rdParams;
  1174.  
  1175.         /** Make sure we get the best possible text face for PostScript performance **/
  1176.         
  1177.         status = MakeOptimalPSTextFace(theStyle);
  1178.         nrequire(status, failed_OptimalFace);
  1179.  
  1180.         /** Get workspace for the text face data structure **/
  1181.         
  1182.         nLayers = GXGetStyleFace(theStyle, nil);
  1183.         status = PSSetWorkSpaceSize(hIEGlobals, sizeof(gxTextFace) + nLayers * sizeof(gxFaceLayer) );
  1184.         nrequire(status, failed_SetWorkSpaceSize);
  1185.  
  1186.         pGlobals = *hIEGlobals;    
  1187.         rdParams = pGlobals->pRDParams;
  1188.  
  1189.         /** Get the text face data **/
  1190.  
  1191.         HLock(pGlobals->hWorkSpace);
  1192.         pFace = (gxTextFace*)*(pGlobals->hWorkSpace);
  1193.         GXGetStyleFace(theStyle, pFace);
  1194.         
  1195.         
  1196.         if ( TestSimpleFace(pFace, theStyle) ) {
  1197.         
  1198.             status = OutputSimpleFaceParams(hIEGlobals, pFace, theStyle);
  1199.             nrequire(status, failed_SimpleFace);
  1200.             
  1201.             rdParams->resIndex = kMakeSimpleLayeredFont;
  1202.             status = RDResPrintf(rdParams);
  1203.             nrequire(status, failed_MakeSimpleFace);
  1204.  
  1205.         } else {
  1206.         
  1207.             status = OutputGeneralFaceParams(hIEGlobals, pFace, theStyle, fontName);
  1208.             nrequire(status, failed_GeneralFace);
  1209.  
  1210.             rdParams->resIndex = kTextFaceFont;
  1211.             status = RDResPrintf(rdParams);
  1212.             nrequire(status, failed_MakeGeneralFace);
  1213.         
  1214.         }//end if
  1215.                     
  1216. failed_MakeGeneralFace:
  1217. failed_GeneralFace:
  1218. failed_MakeSimpleFace:
  1219. failed_SimpleFace:
  1220.  
  1221.         /*** Dispose of any graphics objects created by GXGetStyleFace ***/
  1222.         
  1223.         nLayers = pFace->faceLayers;
  1224.         pLayer = pFace->faceLayer;
  1225.         for (i = 0; i < nLayers; ++i, ++pLayer) {
  1226.         
  1227.             if (pLayer->outlineTransform != nil)
  1228.                 GXDisposeTransform(pLayer->outlineTransform);
  1229.                 
  1230.             if (pLayer->outlineStyle != nil)
  1231.                 GXDisposeStyle(pLayer->outlineStyle);
  1232.                             
  1233.         }//end for
  1234.  
  1235. failed_Dispose:
  1236.  
  1237.         {
  1238.             OSErr        saveStatus;
  1239.             saveStatus = PSReleaseWorkSpace(hIEGlobals);
  1240.             if (status == noErr)
  1241.                 status = saveStatus;
  1242.         }
  1243.         ncheck(status);
  1244.     
  1245. failed_SetWorkSpaceSize:
  1246.  
  1247. failed_OptimalFace:
  1248.  
  1249.         return(status);
  1250.     
  1251.     }//OutputFaceParams
  1252.  
  1253.  
  1254. //<FF>
  1255. /*******************************
  1256.     Routine: EqualTextFace
  1257.     
  1258.     Routine compares two text styles to
  1259.     see if the text faces are equal.
  1260.     
  1261.     This may not be the most robust way of 
  1262.     doing it.  A gx graphics call would be nice.
  1263.     
  1264.     Warning:  Can move memory due to internal allocation.
  1265.     
  1266. *********************************/
  1267. OSErr EqualTextFace(TIEGlobalsHdl hIEGlobals, Boolean *areEqual, gxStyle style1, gxStyle style2);
  1268. OSErr EqualTextFace(TIEGlobalsHdl hIEGlobals, Boolean *areEqual, gxStyle style1, gxStyle style2)
  1269.     {
  1270.         OSErr                    status;
  1271.         TIEGlobalsPtr pGlobals;
  1272.         long                    nLayers1, nLayers2;
  1273.         gxStyle                styleCopy;
  1274.         gxTextFace        *pFace2;
  1275.         long                    faceSize;
  1276.         
  1277.         if (style1 == style2) {
  1278.             *areEqual = true;
  1279.             return(noErr);
  1280.         }//end if
  1281.         
  1282.         if ((style1 == nil) || (style2 == nil)) {
  1283.             *areEqual = false;
  1284.             return(noErr);
  1285.         }//end if
  1286.                 
  1287.         if (GXEqualStyle(style1, style2)) {
  1288.             *areEqual = true;
  1289.             return(noErr);
  1290.         }//end if
  1291.         
  1292.  
  1293.         nLayers1 = GXGetStyleFace(style1, nil);
  1294.         nLayers2 = GXGetStyleFace(style2, nil);
  1295.         
  1296.         if ( (nLayers1 == -1) && (nLayers2 == -1) )    {        // Neither has a face.
  1297.             *areEqual = true;
  1298.             return(noErr);
  1299.         }//end if
  1300.         
  1301.         if (nLayers1 != nLayers2)    {            // different number of layers.
  1302.             *areEqual = false;
  1303.             return(noErr);
  1304.         }//end if
  1305.             
  1306.         /** If we got here, then they both have faces with same # of layers and we must compare them **/
  1307.         
  1308.         faceSize = sizeof(gxTextFace) + nLayers1 * sizeof(gxFaceLayer);
  1309.         
  1310.         status = PSSetWorkSpaceSize(hIEGlobals,  faceSize);
  1311.         nrequire(status, failed_SetSize);
  1312.  
  1313.         pGlobals = *hIEGlobals;
  1314.         HLock(pGlobals->hWorkSpace);
  1315.         
  1316.         pFace2 = (gxTextFace*)*(pGlobals->hWorkSpace);
  1317.         GXGetStyleFace(style2, pFace2);
  1318.         
  1319.         /** Make a copy of style 1 with style-2's text face. ***/
  1320.         
  1321.         styleCopy = GXCopyToStyle(nil, style1);
  1322.         nrequire(status = GXGetGraphicsError(nil), failed_CopyStyle);
  1323.         GXSetStyleFace(styleCopy, pFace2);
  1324.         
  1325.         *areEqual = GXEqualStyle(style1, styleCopy);
  1326.         
  1327.         GXDisposeStyle(styleCopy);
  1328.         
  1329. failed_CopyStyle:        
  1330.         {
  1331.             register OSErr saveStatus = PSReleaseWorkSpace(hIEGlobals);
  1332.             ncheck(saveStatus);
  1333.             
  1334.             if (status == noErr)
  1335.                 status = saveStatus;
  1336.                 
  1337.         }//end block
  1338.             
  1339. failed_SetSize:                
  1340.         return(status);    
  1341.     
  1342.     }//EqualTextFace
  1343.  
  1344. //<FF>
  1345. /*******************************
  1346.     Routine: EqualVariations
  1347.     
  1348.     Routine compares two text styles to
  1349.     see if the variations are equal.
  1350.         
  1351.     Warning:  Can move memory due to internal allocation.
  1352.     
  1353. *********************************/
  1354. OSErr EqualVariations(TIEGlobalsHdl hIEGlobals, Boolean *areEqual, gxStyle style1, gxStyle style2);
  1355. OSErr EqualVariations(TIEGlobalsHdl hIEGlobals, Boolean *areEqual, gxStyle style1, gxStyle style2)
  1356.     {
  1357.         OSErr                                status;
  1358.         TIEGlobalsPtr                pGlobals;
  1359.         long                                nVars1, nVars2;
  1360.         gxFontVariation            *pVariation1, *pVariation2;
  1361.         TFontHandlerContext    fhContext;
  1362.  
  1363.         /* First do the simple tests */
  1364.         
  1365.         if (style1 == style2) {
  1366.             *areEqual = true;
  1367.             return(noErr);
  1368.         }//end if
  1369.         
  1370.         if ((style1 == nil) || (style2 == nil)) {
  1371.             *areEqual = false;
  1372.             return(noErr);
  1373.         }//end if
  1374.                 
  1375.         if (GXEqualStyle(style1, style2)) {
  1376.             *areEqual = true;
  1377.             return(noErr);
  1378.         }//end if
  1379.         
  1380.         /* All calls to get variations go through the font handler wrappers, it knows best */
  1381.         
  1382.         fhContext = (*hIEGlobals)->fhContext;
  1383.         
  1384.         status = FontHandlerGetStyleFontVariations(fhContext, style1, &nVars1, nil);
  1385.         nrequire(status, failed_FHGetVarCount1);
  1386.  
  1387.         status = FontHandlerGetStyleFontVariations(fhContext, style2, &nVars2, nil);
  1388.         nrequire(status, failed_FHGetVarCount2);
  1389.         
  1390.         if ( (nVars1 == 0) && (nVars2 == 0) )    {        // Neither has a variation.
  1391.             *areEqual = true;
  1392.             return(noErr);
  1393.         }//end if
  1394.         
  1395.         if (nVars1 != nVars2)    {            // different number of axes.
  1396.             *areEqual = false;
  1397.             return(noErr);
  1398.         }//end if
  1399.             
  1400.         /** If we got here, then they both have same number of variations, so get them **/
  1401.         
  1402.         status = PSSetWorkSpaceSize(hIEGlobals,  2 * nVars1 * sizeof(gxFontVariation) );
  1403.         nrequire(status, failed_SetSize);
  1404.  
  1405.         pGlobals = *hIEGlobals;
  1406.         HLock(pGlobals->hWorkSpace);
  1407.         
  1408.         pVariation1 = (gxFontVariation*)*(pGlobals->hWorkSpace);
  1409.         pVariation2 = pVariation1 + nVars1;                    // don't you love C pointer arithmetic?
  1410.         
  1411.         status = FontHandlerGetStyleFontVariations(fhContext, style1, nil, pVariation1);
  1412.         nrequire(status, failed_getVar1);
  1413.         
  1414.         status = FontHandlerGetStyleFontVariations(fhContext, style2, nil, pVariation2);
  1415.         nrequire(status, failed_getVar2);
  1416.         
  1417.         /* and compare them */        
  1418.         if ( memcmp( pVariation1, pVariation2, nVars1 * sizeof(gxFontVariation) ) == 0 )
  1419.             *areEqual = true;
  1420.         else
  1421.             *areEqual = false;
  1422.  
  1423. failed_getVar1:
  1424. failed_getVar2:        
  1425.         {
  1426.             register OSErr saveStatus = PSReleaseWorkSpace(hIEGlobals);
  1427.             ncheck(saveStatus);
  1428.             
  1429.             if (status == noErr)
  1430.                 status = saveStatus;
  1431.                 
  1432.         }//end block    
  1433.             
  1434. failed_SetSize:                
  1435. failed_FHGetVarCount2:
  1436. failed_FHGetVarCount1:
  1437.  
  1438.         return(status);    
  1439.     
  1440.     }//EqualVariations
  1441.  
  1442.  
  1443.  
  1444.  
  1445.  
  1446. //<FF>
  1447. /*******************************
  1448.  
  1449.     Function:        TextStylePrimitive
  1450.     
  1451.     Sets the current text style in the current
  1452.     graphics state.  A text style, as far as PostScript
  1453.     is concerned includes the tangent - since this requires
  1454.     making a new font dictionary.
  1455.     
  1456.     hIEGLobals:                imaging engine globals handle.
  1457.     textStyle:                style for this piece of text.
  1458.     pTangent:                    tangent vector for this piece of text.
  1459.     
  1460. *********************************/
  1461. OSErr    _TextStylePrimitive(TIEGlobalsHdl hIEGlobals, gxStyle textStyle, gxPoint* pTangent)
  1462.     {
  1463.         OSErr                        status;                                // error?
  1464.         TIEGlobalsPtr        pGlobals;                            // dereference the globals.
  1465.         Fixed                        fontSize;                            // point size for font.
  1466.         Fixed                        a, b, c, d;                        // Parameters for SFt PostScript procedure.
  1467.         fhFont                    theFont;                            // font resource id.
  1468.         long                        child;                                // Child font index.
  1469.         Str255                    fontName;                            // name of the font to set on the printer.
  1470.         TRDParams                *rdParams;                        // RD Parameter block.
  1471.         Boolean                    hasFace;                            // Does it have a text face?
  1472.         Boolean                    fontSwapped = false;    // Did we do a font change?
  1473.         Boolean                    facesEqual;                        // is text face the same as before?
  1474.         Boolean                    variationsEqual;            // are the font variations same sas before?
  1475.         TFHSaveResult        fhSaveResult;                    // save-level result from the font handler.
  1476.     
  1477.         status = FontHandlerGetStyleFont((*hIEGlobals)->fhContext, textStyle, &theFont);
  1478.         nrequire(status, failed_getfont);
  1479.  
  1480.         fontSize = GXGetStyleTextSize(textStyle);
  1481.         
  1482.         pGlobals = *hIEGlobals;
  1483.         rdParams = pGlobals->pRDParams;
  1484.         
  1485.         /*****
  1486.                 Always make sure the font is avalialble, even if it is the same font as before
  1487.                     cause a restore could have happened and flushed it
  1488.         *******/
  1489.  
  1490.         /** MakeFontAvailable can send the buffer data message **/
  1491.         status = RDFlushBuffer(rdParams->rdMap);
  1492.         nrequire(status, failed_rdFlush);
  1493.  
  1494.         status = FontHandlerMakeFontAvailable(pGlobals->fhContext, textStyle, &child, fontName, &fhSaveResult);
  1495.         nrequire(status, failed_FHMFA);
  1496.  
  1497.         status = EqualTextFace(hIEGlobals, &facesEqual, (*hIEGlobals)->textStyle, textStyle);
  1498.         nrequire(status, failed_EqualFace);
  1499.         
  1500.         status = EqualVariations(hIEGlobals, &variationsEqual, (*hIEGlobals)->textStyle, textStyle);
  1501.         nrequire(status, failed_EqualVariations);
  1502.                         
  1503.         /**************
  1504.             Deal with font handler memory state, in case it did a save or a restore
  1505.             or a combination restore/save
  1506.         **************/
  1507.         if (fhSaveResult != fhNoChange) {
  1508.         
  1509.             status = FixGraphicsState(hIEGlobals, (fhSaveResult & fhDidRestore) ? true : false,
  1510.                                                                                          (fhSaveResult & fhDidSave) ? true : false);
  1511.             nrequire(status, failed_FixGraphicsState);
  1512.             
  1513.         }//end if
  1514.  
  1515.         
  1516.         /************
  1517.             Do the text style:
  1518.             
  1519.             First make sure the current font dictionary reflects all of the
  1520.                 style craziness such as variations and text faces.
  1521.             
  1522.             Second, deal with the font size and tangent.
  1523.             
  1524.         ************/
  1525.  
  1526.         hasFace = TestStyleFace(textStyle);
  1527.  
  1528.         pGlobals = *hIEGlobals;                // In case the handle moved.
  1529.         
  1530.         if ( (pGlobals->theFont != theFont) || (pGlobals->fontChild != child) ||
  1531.                  (!facesEqual) || (!variationsEqual) || (pGlobals->ieStateFlags & eFontOutOfDate) ) {
  1532.         
  1533.             /* Get the font dictionary on the stack */
  1534.             
  1535.             rdParams->resIndex = kFindFont;
  1536.             status = RDResPrintf(rdParams,  fontName);
  1537.             nrequire(status, failed_FindFont);
  1538.             
  1539.             /** Update the font and child state in our globals **/
  1540.             
  1541.             pGlobals = *hIEGlobals;
  1542.             pGlobals->theFont = theFont;
  1543.             pGlobals->fontChild = child;
  1544.             
  1545.             /* Apply any variations to it */
  1546.             
  1547.             status = RDFlushBuffer(rdParams->rdMap);            // calling font handler can send buffer data.
  1548.             nrequire(status, failed_rdFlush1);
  1549.             status = FontHandlerOutputVariationPSOperator((*hIEGlobals)->fhContext, textStyle);
  1550.             nrequire(status, failed_variations);
  1551.             
  1552.             /* Apply any text face to it */
  1553.             
  1554.             if (hasFace) {
  1555.                             
  1556.                 status = OutputFaceParams(hIEGlobals, textStyle, fontName);
  1557.                 nrequire(status, failed_Face);
  1558.                 
  1559.             }//end if
  1560.             
  1561.             /* Make the font with the text face and variations applied to it into the current base font */
  1562.             
  1563.             rdParams->resIndex = kSetBaseFont;
  1564.             nrequire(status = RDResPrintf(rdParams), failed_SetBaseFont);
  1565.             fontSwapped = true;
  1566.         
  1567.         }//end if
  1568.         
  1569.         
  1570.         /*** If necessary, apply the tangent/size combination to the base font in our state ****/
  1571.  
  1572.         pGlobals = *hIEGlobals;
  1573.         
  1574.         if ( (pGlobals->fontSize != fontSize) ||
  1575.                  (pGlobals->fontTangent.x != pTangent->x) ||
  1576.                  (pGlobals->fontTangent.y != pTangent->y) ||
  1577.                  fontSwapped ) {
  1578.         
  1579.             pGlobals->fontSize = fontSize;
  1580.             pGlobals->fontTangent = *pTangent;
  1581.         
  1582.             /*****
  1583.                 if the font swapped flag is true, then the above operations left the base font
  1584.                 dictionary on the stack.  If it is false, we must get it out of the augmented
  1585.                 graphics state.
  1586.             *****/
  1587.             if (!fontSwapped) {                
  1588.             
  1589.                 rdParams->resIndex = kCurrBaseFont;
  1590.                 nrequire(status = RDResPrintf(rdParams), failed_SelectFont);
  1591.  
  1592.             }//end if
  1593.             
  1594.             /** Apply the tangent to the base font on the operand stack **/
  1595.             
  1596.             // Construct the parameters for the SFt operator.  (Text face font dicts are flipped in y so deal)
  1597.             
  1598.             a = FixedMultiply( pTangent->x, fontSize);
  1599.             b = FixedMultiply( pTangent->y, fontSize);
  1600.             c = FixedMultiply(-pTangent->y, fontSize); if (!hasFace) c = -c;
  1601.             d = FixedMultiply( pTangent->x, fontSize); if (!hasFace) d = -d;
  1602.             
  1603.             rdParams->resIndex = kTangentFont;
  1604.             nrequire(status = RDResPrintf(rdParams, a, b, c, d), failed_SelectFont);
  1605.                     
  1606.         }//end if
  1607.         
  1608.         /** Update the text style in our global state **/
  1609.         
  1610.         pGlobals = *hIEGlobals;
  1611.         if (pGlobals->textStyle != nil)
  1612.             GXDisposeStyle(pGlobals->textStyle);
  1613.             
  1614.         (*hIEGlobals)->textStyle = GXCloneStyle(textStyle);
  1615.         
  1616.         /** Note that the font is up to date so we don't reset it needlessly **/
  1617.         
  1618.         (*hIEGlobals)->ieStateFlags &= ~eFontOutOfDate;
  1619.         
  1620. failed_SelectFont:
  1621. failed_SetBaseFont:
  1622. failed_Face:
  1623. failed_variations:
  1624. failed_rdFlush1:
  1625. failed_FindFont:
  1626. failed_FixGraphicsState:
  1627. failed_EqualVariations:
  1628. failed_EqualFace:
  1629. failed_FHMFA:
  1630. failed_rdFlush:
  1631. failed_getfont:
  1632.  
  1633.         return(status);
  1634.     
  1635.     }//TextStylePrimitive
  1636.     
  1637.